package queued

import (
	"amusing-pkg/maputils"
	"container/list"
	"errors"
	"sync"
	"sync/atomic"
	"time"
)

const (
	QueueStatusClose   uint32 = iota // 关闭
	QueueStatusOpen                  // 开启
	QueueStatusWaiting               // 正在排队中
	QueueStatusStop                  // 停止
)

type PushQueueType int32

const (
	// PushQueueTypeFront for retry
	PushQueueTypeFront PushQueueType = iota + 1
	// PushQueueTypeBack for Normal
	PushQueueTypeBack
)

type QueueList interface {
}

type queueTask struct {
	pushType PushQueueType
	doTask   WaitingQueuedJob
}

// 排队队列 （无锁编码）
type queuedRingList struct {
	// 每次任务调度数
	state     *atomic.Uint32 // 当前排队队列状态
	list      *list.List     // 循环列表
	rwLock    *sync.RWMutex
	taskMap   *maputils.Map[uint64, *list.Element] // 元素Key用于获取 *Element
	processCh chan struct{}                        // 用于处理任务的信号通道
	waitTime  time.Duration                        // 重试等待时间
}

type QueuedRingList interface {
	Remove(jobID uint64) bool
	GetQueueLength() int
	GetCurrentState() uint32
	PushBackTask(task WaitingQueuedJob)
	PushFrontTask(task WaitingQueuedJob)
	Run() error
}

func NewQueuedRingList(waitTime time.Duration) QueuedRingList {
	var state = new(atomic.Uint32)
	state.Store(QueueStatusStop)
	return &queuedRingList{
		waitTime:  waitTime,
		state:     state,
		list:      list.New(),
		rwLock:    new(sync.RWMutex),
		taskMap:   maputils.New[uint64, *list.Element](),
		processCh: make(chan struct{}, 1), // 使用缓冲通道来确保信号不丢失

	}
}

func (q *queuedRingList) GetCurrentState() uint32 {
	return q.state.Load()
}

// GetQueueLength 获取当前排队长度
func (q *queuedRingList) GetQueueLength() int {
	q.rwLock.RLock()
	defer q.rwLock.RUnlock()
	return q.list.Len()
}

// GetPosition 获取指定任务在队列中的位置
func (q *queuedRingList) GetPosition(jobID uint64) int {
	q.rwLock.RLock()
	defer q.rwLock.RUnlock()

	position := 0
	for e := q.list.Front(); e != nil; e = e.Next() {
		_queueTask, ok := e.Value.(*queueTask)
		if ok && _queueTask.doTask.GetJobID() == jobID {
			return position
		}
		position++
	}
	return -1 // 如果找不到返回 -1
}

// Remove remove task
func (q *queuedRingList) Remove(jobID uint64) bool {
	e, ok := q.taskMap.Load(jobID)
	if !ok {
		// 没有就是已经删除成功
		return true
	}
	_queueTask := e.Value.(*queueTask)
	if _queueTask != nil && _queueTask.doTask.IsDoing() {
		return false
	}
	q.rwLock.Lock()
	defer q.rwLock.Unlock()
	// remove list
	q.list.Remove(e)
	// remove taskMap
	q.taskMap.Delete(jobID)
	return true
}

// RemoveElement remove task
func (q *queuedRingList) RemoveElement(e *list.Element, jobID uint64) bool {
	q.rwLock.Lock()
	defer q.rwLock.Unlock()

	// remove list
	q.list.Remove(e)
	// remove taskMap
	q.taskMap.Delete(jobID)
	return true
}

func (q *queuedRingList) GetFrontElement() *list.Element {
	q.rwLock.RLock()
	defer q.rwLock.RUnlock()
	return q.list.Front()
}

func (q *queuedRingList) GetBackElement() *list.Element {
	q.rwLock.RLock()
	defer q.rwLock.RUnlock()
	return q.list.Back()
}

func (q *queuedRingList) PushBackTask(task WaitingQueuedJob) {
	q.rwLock.Lock()
	defer q.rwLock.Unlock()
	// 尝试获取当前 element
	_e, _ok := q.taskMap.Load(task.GetJobID())
	if _ok {
		q.list.Remove(_e)
	}

	e := q.list.PushBack(&queueTask{
		pushType: PushQueueTypeBack,
		doTask:   task,
	})
	// cover the element
	q.taskMap.Store(task.GetJobID(), e)
	select {
	case q.processCh <- struct{}{}:
	default:
	}
}

func (q *queuedRingList) PushFrontTask(task WaitingQueuedJob) {
	q.rwLock.Lock()
	defer q.rwLock.Unlock()
	// 尝试获取当前 element
	_e, _ok := q.taskMap.Load(task.GetJobID())
	if _ok {
		q.list.Remove(_e)
	}

	e := q.list.PushFront(&queueTask{
		pushType: PushQueueTypeFront,
		doTask:   task,
	})
	// cover the element
	q.taskMap.Store(task.GetJobID(), e)
	select {
	case q.processCh <- struct{}{}:
	default:
	}
}

func (q *queuedRingList) processJobs() {
	for {
		for range q.processCh {
			//<-q.processCh
			q.state.Store(QueueStatusWaiting)
			for {
				frontE := q.GetFrontElement()
				if frontE == nil {
					// 没有队列任务了
					q.state.Store(QueueStatusOpen)
					break
				}
				_queueTask := frontE.Value.(*queueTask)

				jobID := _queueTask.doTask.GetJobID()
				// 排队机制同步执行
				jobResType := _queueTask.doTask.RunJob()
				switch jobResType {
				case JobSuccess:
					q.Remove(jobID)
				case JobFail:
					if _queueTask.doTask.Abort() {
						q.Remove(jobID)
					}
				case JobRePush:
					q.PushFrontTask(_queueTask.doTask)
					// 需要等待
					time.Sleep(q.waitTime)
					//case JobRePushBack:
					//	q.PushBackTask(_queueTask.doTask)
					//case JobRePushFront:
					//	q.PushFrontTask(_queueTask.doTask)
				}

			}

		}

		q.state.Store(QueueStatusOpen)
	}

}

func (q *queuedRingList) Run() error {
	if q.state.Load() != QueueStatusStop {
		return errors.New("queue can not run")
	}

	q.state.Store(QueueStatusOpen)

	go q.processJobs()

	return nil
}
